/* Parse a configuration file into a struct using X-Macros */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>

#include "utils.h"
#include "kc031service.h"
#ifdef USE_UEVENT
#include <linux/netlink.h>
#endif
#include "ringBuffer.h"
#include "lua.h"
#include "mqtt.h"
#include "hqjgdata.h"
#include "aexudp.h"
#include "version.h"
#include "mt_timer.h"
#include "sgw_device.h"

extern char *app_version_get(void);

static psus_config psus_data; // 从配置文件中读取的服务端配置数据

int TcpTryConnect(psus_config *psudata);

/* create one and fill in its default values */
psus_config Psus_Config_Default = {
#define CFG(s, n, default) default,
#include "psuservice.def"
	{
		.flag = 0x11,
		.minLevel = 5,
		.maxLevel = 10,
		.selectTimeout = -1,
		.localport = 5000,
		.nettype = 0,
		.tcp_addr = {},
		.udp_addr = {},
		.tcp_fd = -1,
		.bsuart = {
			.uart_used = 1,	
			.uart_fd = -1,
			.type = AEX_UART_RS485,		
		},
		.last_cmd_from = AEX_LCF_NONE,
		.uevent_fd = -1,
		.etype = 0,
	},
};

/* process a line of the INI file, storing valid values into config struct */
static int handler(void *user, const char *section, const char *name, const char *value)
{
	psus_config *cfg = (psus_config *)user;

	if (0)
		;
#define CFG(s, n, default)                                      \
	else if (strcmp(section, #s) == 0 && strcmp(name, #n) == 0) \
	{                                                           \
		if (value != NULL)                                      \
			cfg->s##_##n = strdup(value);                       \
		else                                                    \
			cfg->s##_##n = strdup("");                          \
	}
#include "psuservice.def"

	return 1;
}

/* print all the variables in the config, one per line */
static void dump_config(psus_config *cfg)
{
	printf("\nconfig:{\n");
#define CFG(s, n, default) printf("%s_%s = %s\n", #s, #n, cfg->s##_##n == NULL ? "" : cfg->s##_##n);
#include "psuservice.def"
	printf("\n}config end.\n");
}

/* clear all the variables in the config, one per line */
static void clear_config(psus_config *cfg)
{
#define CFG(s, n, default)    \
	if (cfg->s##_##n != NULL) \
	{                         \
		free(cfg->s##_##n);   \
		cfg->s##_##n = NULL;  \
	}
#include "psuservice.def"
}

/* clear all the variables in the config, one per line */
static void save_config(psus_config *cfg, char *file)
{
// printf("%s = %d\n",__func__,__LINE__);
#define CFG(s, n, default) write_profile_string(#s, #n, cfg->s##_##n, file);
#include "psuservice.def"
}

static void default_config(psus_config *cfg, psus_config *defcfg)
{
// printf("%s = %d\n",__func__,__LINE__);
#define CFG(s, n, default)       \
	if (cfg->s##_##n != NULL)    \
		free(cfg->s##_##n);      \
	if (defcfg->s##_##n != NULL) \
		cfg->s##_##n = strdup(defcfg->s##_##n);
#include "psuservice.def"
}

/*
	设置启动和关闭输出到文件的标识。
*/
void _set_debug_file(int v)
{
	if (v == 0)
	{
		psus_data.hcsdata.flag &= ~DEBUG_FILE;
	}
	else
	{
		psus_data.hcsdata.flag |= DEBUG_FILE;
	}
}

/*
	最终输出日志的函数，输出位置使用psu_data的flag变量的设置。可以选择是输出到控制台还是文件。
*/
static void _log_message(int Level, char *msgstr)
{
	_log(psus_data.log_file, psus_data.hcsdata.flag, msgstr);
}

/*
	最终输出错误的函数，错误信息会同时输出到控制台和文件。
*/
static void _log_error(char *msgstr)
{
	_log(psus_data.log_file, 0x11, msgstr);
}

/*
	最终输出告警的函数，告警信息会同时输出到控制台和文件。
*/
static void _log_warning(char *msgstr)
{
	_log(psus_data.log_file, 0x11, msgstr);
}

// 外部获取平台库配置的数据结构的方法
psus_config *get_psus_data(void)
{
	return &psus_data;
}

void gen_uuid(unsigned char *uuid)
{
	char GUID[40];
	int t = 0;
	// char *szTemp = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
	char *szTemp = "4xxxxxxxxxxx4xxxyxxx";
	char *szHex = "0123456789ABCDEF-";
	int nLen = strlen (szTemp);

	srand (clock());
	for (t=0; t<nLen+1; t++)
	{
		int r = rand () % 16;
		char c = ' ';   

		switch (szTemp[t])
		{
			case 'x' : { c = szHex [r]; } break;
			case 'y' : { c = szHex [r & 0x03 | 0x08]; } break;
			case '-' : { c = '-'; } break;
			case '4' : { c = '4'; } break;
		}

		GUID[t] = ( t < nLen ) ? c : 0x00;
	}
	sprintf(uuid,"%s", GUID);
}

/**
	从配置文件读取配置的函数，当管理命令需要执行载入配置命令时可以使用此函数
*/
static int LoadPsuConfig(char *fn)
{
	int r = TRUE;
	int i;
	psus_config *psudata = get_psus_data();
	int ret = 1;
	unsigned short port;

	SetLogCallback(_log_message, _log_warning, _log_error);
	if (ini_parse(fn, handler, &psus_data) < 0)
	{
		psus_error("Can't load '%s', using defaults", fn);
		default_config(psudata, &Psus_Config_Default);
		// if(strlen(psudata->main_uuid)==0){
		// 	char uuid[30];
		// 	gen_uuid(uuid);
		// 	if(psudata->main_uuid)free(psudata->main_uuid);
		// 	psudata->main_uuid = strdup(uuid);
		// }
		// if (psudata->main_version)
		// 	free(psudata->main_version);
		// psudata->main_version = strdup(app_version_get());
		save_config(psudata, fn);
		r = FALSE;
	}
	dump_config(&psus_data);

	// // if (psudata->main_version)
	// // 	free(psudata->main_version);
	// psudata->main_version = strdup(app_version_get());
	psudata->hcsdata.flag = StrToInt(psudata->log_flag);
	psudata->hcsdata.minLevel = StrToInt(psudata->log_minLevel);
	psudata->hcsdata.maxLevel = StrToInt(psudata->log_maxLevel);
	SetLogLevel(psudata->hcsdata.minLevel, psudata->hcsdata.maxLevel);

	psudata->hcsdata.selectTimeout = StrToInt(psudata->service_selectTimeout);

	// 初始化TCP服务器Socket地址信息
	unsigned int addr;
	memset(&(psudata->hcsdata.tcp_addr), 0, sizeof(struct sockaddr));
	addr = ParseIPAddr(psudata->server_tcpaddr, &port);
	psudata->hcsdata.tcp_addr.sin_family = AF_INET;
	psudata->hcsdata.tcp_addr.sin_addr.s_addr = addr;
	psudata->hcsdata.tcp_addr.sin_port = htons(port);

	// 初始化UDP服务器Socket地址信息
	memset(&(psudata->hcsdata.udp_addr), 0, sizeof(struct sockaddr));
	addr = ParseIPAddr(psudata->server_udpaddr, &port);
	psudata->hcsdata.udp_addr.sin_family = AF_INET;
	psudata->hcsdata.udp_addr.sin_addr.s_addr = addr;
	psudata->hcsdata.udp_addr.sin_port = htons(port);
	psudata->hcsdata.localport = StrToInt(psudata->service_localport);

	psudata->hcsdata.hasgpio = StrToInt(psudata->main_hasgpio);

	#ifdef SGWEC_BOARD
		psudata->hcsdata.bsuart.uart_used = StrToInt(psudata->uart_used);
		psudata->hcsdata.bsuart.type = StrToInt(psudata->uart_type);		//底板上的串口只使用RS485
		psudata->hcsdata.bsuart.port = psudata->uart_port;
		psudata->hcsdata.bsuart.passto = StrToInt(psudata->uart_passto);
		psudata->hcsdata.bsuart.uart_fd = INVAILDSOCKET;
		// psudata->hcsdata.hasgpio = StrToInt(psudata->main_hasgpio);
		// psudata->hcsdata.autoserver = StrToInt(psudata->network_autoserver);

		psudata->hcsdata.uarts[0].uart_used = StrToInt(psudata->uart1_used);
		psudata->hcsdata.uarts[0].type = StrToInt(psudata->uart1_type);
		psudata->hcsdata.uarts[0].port = psudata->uart1_port;
		psudata->hcsdata.uarts[0].passto = StrToInt(psudata->uart1_passto);
		psudata->hcsdata.uarts[0].uart_fd = INVAILDSOCKET;

		psudata->hcsdata.uarts[1].uart_used = StrToInt(psudata->uart2_used);
		psudata->hcsdata.uarts[1].type = StrToInt(psudata->uart2_type);
		psudata->hcsdata.uarts[1].port = psudata->uart2_port;
		psudata->hcsdata.uarts[1].passto = StrToInt(psudata->uart2_passto);
		psudata->hcsdata.uarts[1].uart_fd = INVAILDSOCKET;
	#else
		psudata->hcsdata.bsuart.uart_used = StrToInt(psudata->uart_used);
		psudata->hcsdata.bsuart.type = StrToInt(psudata->uart_type);		
		psudata->hcsdata.bsuart.port = psudata->uart_port;
		psudata->hcsdata.bsuart.passto = StrToInt(psudata->uart_passto);
		psudata->hcsdata.bsuart.uart_fd = INVAILDSOCKET;

		psudata->hcsdata.uarts[0].uart_used = StrToInt(psudata->uart1_used);
		psudata->hcsdata.uarts[0].type = StrToInt(psudata->uart1_type);
		psudata->hcsdata.uarts[0].port = psudata->uart1_port;
		psudata->hcsdata.uarts[0].passto = StrToInt(psudata->uart1_passto);
		psudata->hcsdata.uarts[0].uart_fd = INVAILDSOCKET;

	#endif
	psudata->hcsdata.udp_fd = INVAILDSOCKET;
	psudata->hcsdata.tcp_fd = INVAILDSOCKET;
	psudata->hcsdata.uevent_fd = INVAILDSOCKET;
	psudata->hcsdata.etype = StrToInt(psudata->encrypt_etype);
	if(psudata->encrypt_ekey != NULL && (strlen(psudata->encrypt_ekey) >= 16)){
		psus_hint("KEY:%s(%d)",psudata->encrypt_ekey,strlen(psudata->encrypt_ekey));
		dump_buffer("",psudata->encrypt_ekey,16);
		int len=16;
		HexDecode(psudata->encrypt_ekey,32,psudata->hcsdata.ekey,&len);
		dump_buffer("",psudata->hcsdata.ekey,16);
	}
	
	return r;
}

// void dump_buffer(char *pstr, int size)
// {
// 	char buf[40];
// 	int hexlen = sizeof(buf);
// 	char *p = pstr;

// 	while (size > 0)
// 	{
// 		memset(buf, 0, sizeof(buf));
// 		hexlen = sizeof(buf);
// 		HexEncode(p, MIN(16, size), buf, &hexlen);
// 		psus_hint("\t%s ", buf);
// 		p += 16;
// 		size -= 16;
// 	}
// }

/**
 * @brief 打开管理串口
 * 
 * @param psudata 
 * @return int 
 */
int OpenUart(UARTDATA *puart)
{
	if(puart->uart_used){
		if (puart->uart_fd > INVAILDSOCKET)
			return puart->uart_fd;
		puart->uart_fd = com_open(puart->port, O_RDWR | O_NOCTTY | O_NONBLOCK);
		if (puart->uart_fd <= 0)
		{
			aexgpio_set_bus_status(0);
			psus_error("open uart %s error:%s", puart->port, strerror(errno));
			return -1;
		}
		return puart->uart_fd;
	}else{
		if(puart == &psus_data.hcsdata.bsuart)
			aexgpio_set_bus_status(0);				//如果是底板的写串口则设置 bus 状态
		return INVAILDSOCKET;
	}
}

/**
 * @brief 关闭管理串口
 * 
 * @param psudata 
 */
void CloseUart(UARTDATA *puart)
{
	if(puart == &psus_data.hcsdata.bsuart)
		aexgpio_set_bus_status(0);			//如果是底板的写串口则设置 bus 状态
	if(puart->uart_used){
		if (puart->uart_fd > 0)
			close(puart->uart_fd);
		puart->uart_fd = 0;
	}
}

char *IP2Str(unsigned long ip)
{
	static char buf[20];

	sprintf(buf, "%d.%d.%d.%d", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
	return buf;
}

int StartUdpSocket(psus_config *psudata)
{
	struct sockaddr_in addr;

	if (psudata->hcsdata.udp_fd > INVAILDSOCKET)
	{
		// 如果已经创建了此socket，那么直接返回避免重复创建
		return psudata->hcsdata.udp_fd;
	}
	if ((psudata->hcsdata.udp_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		psus_error("Udp socket error:%s", strerror(errno));
		return -1;
	}

	/*if(!SetNonblocking(psudata->udp_fd)){
		psus_warning("set socket %d nonblocking fail.",psudata->udp_fd);
	}*/
 	int broadcast_enable = 1;
    if (setsockopt(psudata->hcsdata.udp_fd , SOL_SOCKET, SO_BROADCAST, 
                  &broadcast_enable, sizeof(broadcast_enable)) < 0) {
        psus_error("setsockopt(SO_BROADCAST) failed");
    }
	memset(&addr, 0, sizeof(struct sockaddr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(psudata->hcsdata.localport);
	if (bind(psudata->hcsdata.udp_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1)
	{
		psus_error("Udp bind socket error:%d", ntohs(addr.sin_port));
		close(psudata->hcsdata.udp_fd);
		psudata->hcsdata.udp_fd = 0;
		return -2;
	}
	psus_log(10, "Udp socket bind to %d(%d)...", ntohs(addr.sin_port),psudata->hcsdata.localport);
	return psudata->hcsdata.udp_fd;
}

int StartUdpSocketClient(psus_config *psudata)
{
	int udp_fd = 0;
	struct sockaddr_in addr;

	if ((udp_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		psus_error("Udp client socket error:%s", strerror(errno));
		return -1;
	}

 	int broadcast_enable = 1;
    if (setsockopt(udp_fd , SOL_SOCKET, SO_BROADCAST, 
                  &broadcast_enable, sizeof(broadcast_enable)) < 0) {
        psus_error("setsockopt(SO_BROADCAST) failed");
    }
	memset(&addr, 0, sizeof(struct sockaddr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(0);
	if (bind(udp_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1)
	{
		psus_error("Udp bind socket error:%d", 0);
		close(udp_fd);
		udp_fd = INVAILDSOCKET;
	}
	psus_log(10, "Udp client socket bind to %d...", ntohs(addr.sin_port));
	return udp_fd;
}

void CloseUdpSocket(psus_config *psudata)
{
	if (psudata->hcsdata.udp_fd > INVAILDSOCKET)
	{
		close(psudata->hcsdata.udp_fd);
		psudata->hcsdata.udp_fd = INVAILDSOCKET;
	}
}

int SendToMqttServer(psus_config *psudata, char *buf, int len)
{
	int ret = 0;
	if(get_mqtt_connected()){
		// psus_hint("Send mqtt %s from me",cmd);
		mqtt_pub(buf, len);
		ret = len;	//strlen(cmd);
	}else{
		char cmd[256];
		int cmdlen = sizeof(cmd);

		memset(cmd, 0, sizeof(cmd));
		HexEncode(buf, len, cmd, &cmdlen);
		psus_hint("Send mqtt %s ,but mqtt not connected.",cmd);
	}
	return ret;
}

int SendtoTcpServer(psus_config *psudata, char *buf, int len)
{
	int ret = 0;

	if (psudata->hcsdata.tcp_fd > INVAILDSOCKET && get_tcp_connected())
	{
		psus_hint("RSP:%d", len);
		dump_buffer("",buf, len);
		psus_hint("Send tcp to %s:%d", IP2Str(psudata->hcsdata.tcp_addr.sin_addr.s_addr), ntohs(psudata->hcsdata.tcp_addr.sin_port));
		ret = write(psudata->hcsdata.tcp_fd, buf, len);
		//TCP连接、发送、关闭
	}
	return ret;
}

int SendtoRS485Bus(psus_config *psudata,unsigned char dstaddr,unsigned char cmd, char *pdata, int plen)
{
	int ret = 0;
	char buf[255];

	psus_hint("%s:%d",__func__,__LINE__);
	PPKTPROPO handle = aexudp_get_default_prkpropo();
	{
		memset(buf,0,sizeof(buf));
		AEXUDP_SET_BEGIN(buf,handle->start);
		AEXUDP_SET_INDEX(buf,aexudp_get_packnet_index());
		AEXUDP_SET_CMD(buf,cmd);
		AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(buf),aexgpio_get_mod_addr());		//设置源地址为边缘计算
		AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(buf),dstaddr);						//设置目标地址
		AEXUDP_DATA_SET_PAYLOAD(AEXUDP_GET_DATA(buf),pdata,plen);	
		AEXUDP_SET_LEN(buf,plen+2);	
		if(handle->encrypt){
			handle->encrypt(buf,AEXUDP_GET_LEN(buf));
		}else{
			AEXUDP_SET_CRC(buf);
		}
		AEXUDP_SET_END(buf,handle->end);
	}
	psus_hint("Send Buffer:");
	dump_buffer("",buf,AEXUDP_GET_PACKET_LEN(buf));
	psus_hint("%s:%d,dstaddr=%02X,is_slot_broadcast=%d",__func__,__LINE__,dstaddr,is_slot_broadcast(dstaddr));
	if(is_slot_broadcast(dstaddr)){
		//目标为插槽上模块的广播数据包
		if (psudata->hcsdata.bsuart.uart_used && psudata->hcsdata.bsuart.uart_fd > INVAILDSOCKET)
		{
			#ifdef SGWEC_BOARD
				psus_hint("%s:%d sendto.",__func__,__LINE__);
				ret = modgpio_rs485_write(psudata->hcsdata.bsuart.uart_fd, buf,  AEXUDP_GET_PACKET_LEN(buf));
			#else
				ret = modgpio_rs485_write(psudata->hcsdata.bsuart.uart_fd, buf, AEXUDP_GET_PACKET_LEN(buf));
			#endif
		}
		psus_hint("%s:%d,psudata->hcsdata.udp_fd=%d",__func__,__LINE__,psudata->hcsdata.udp_fd);
		if (psudata->hcsdata.udp_fd > INVAILDSOCKET)
		{
			//通过网络发送广播，自己也会收到，通过dst和src过滤
			foreach_ifname_broadcast(psudata->hcsdata.udp_fd,psudata->hcsdata.localport+1,buf,AEXUDP_GET_PACKET_LEN(buf));
		}
	}else{
		//特定模块的数据包
		psus_hint("%s:%d,dstaddr=%02X,sgw_device_has_net=%d",__func__,__LINE__,dstaddr,sgw_device_has_net(dstaddr));
		if(sgw_device_has_net(dstaddr)){
			int udp_fd = psudata->hcsdata.udp_fd;
			if (udp_fd > INVAILDSOCKET)
			{
				//通过网络发送广播，自己也会收到，通过dst和src过滤
				foreach_ifname_broadcast(udp_fd,psudata->hcsdata.localport+1,buf,AEXUDP_GET_PACKET_LEN(buf));
			}
		}else{
			if (psudata->hcsdata.bsuart.uart_used && psudata->hcsdata.bsuart.uart_fd > INVAILDSOCKET)
			{
				#ifdef SGWEC_BOARD
					psus_hint("%s:%d",__func__,__LINE__);
					ret = modgpio_rs485_write(psudata->hcsdata.bsuart.uart_fd, buf,  AEXUDP_GET_PACKET_LEN(buf));
				#else
					ret = modgpio_rs485_write(psudata->hcsdata.bsuart.uart_fd, buf, AEXUDP_GET_PACKET_LEN(buf));
				#endif
			}
		}
	}
	return ret;
}

/**
 * @brief 使用UDP协议发送数据给服务器
 *
 * @param psudata
 * @param buf
 * @param len
 * @return int
 */
int SendtoUdpServer(psus_config *psudata, char *buf, int len)
{
	int ret = 0;

	if (psudata->hcsdata.udp_fd > INVAILDSOCKET)
	{
		psus_hint("RSP:%d", len);
		dump_buffer("",buf, len);
		psus_hint("Send udp to %s:%d", IP2Str(psudata->hcsdata.udp_addr.sin_addr.s_addr), ntohs(psudata->hcsdata.udp_addr.sin_port));
		ret = sendto(psudata->hcsdata.udp_fd, buf, len, 0, (struct sockaddr *)&psudata->hcsdata.udp_addr, sizeof(struct sockaddr));
	}
	return ret;
}

int SendtoServer(char *buf, int len)
{
	psus_config *psudata = get_psus_data();

	switch(psudata->hcsdata.nettype){
	case 0:
		return SendToMqttServer(psudata,buf,len);
	case 1:
		return SendtoTcpServer(psudata,buf,len);
	case 2:
		return SendtoUdpServer(psudata,buf,len);
	}
}

/**
 * @brief 通过UDP给自己发送指令的函数
 *
 * @param cmd
 * @param len
 */
void SendtoMe(char *cmd, int len)
{
	psus_config *psudata = get_psus_data();
	int udp_fd = StartUdpSocketClient(psudata);
	if (udp_fd > INVAILDSOCKET)
	{
		struct sockaddr_in net_addr;

		memset(&net_addr, 0, sizeof(struct sockaddr));
		net_addr.sin_family = AF_INET;
		net_addr.sin_addr.s_addr = htonl(0x7F000001);
		net_addr.sin_port = psudata->hcsdata.udp_addr.sin_port;

		psus_hint("CMD:%d", len);
		dump_buffer("",cmd, len);
		psus_hint("Send to me %s:%d", IP2Str(net_addr.sin_addr.s_addr), ntohs(net_addr.sin_port));
		psudata->hcsdata.last_cmd_from = AEX_LCF_ME; // 给自己发数据
		if (sendto(udp_fd, cmd, len, 0, (struct sockaddr *)&net_addr, sizeof(struct sockaddr)) != -1)
		{
			psus_hint("\tOK.");
		}
		else
		{
			psus_hint("\tFail:%s", strerror(errno));
		}

		close(udp_fd);
	}
}

static int tcp_connected = 0;

int get_tcp_connected()
{
	return tcp_connected;
}

int StartTcpSocket(psus_config *psudata)
{
	if (psudata->hcsdata.tcp_fd > INVAILDSOCKET)
	{
		// 如果已经创建了此socket，那么直接返回避免重复创建
		if(tcp_connected == -3){
			tcp_connected = 0;
			CloseTcpSocket(psudata);	//上一次循环链接失败,关闭tcp,本轮循环不做处理,下次循环重新创建并连接tcp
			return INVAILDSOCKET;
		}else{
			return psudata->hcsdata.tcp_fd;
		}
	}
	if ((psudata->hcsdata.tcp_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		psus_error("TCP Service socket error:%s", strerror(errno));
		return -1;
	}

	struct timeval timeout;
	timeout.tv_sec = 10;
	timeout.tv_usec = 0;
	socklen_t len = sizeof(struct timeval);
	if (setsockopt(psudata->hcsdata.tcp_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len) == -1)
	{
		psus_error("TCP Socket setsockopt error [%d]: %s", errno, strerror(errno));
	}

	if (!SetNonblocking(psudata->hcsdata.tcp_fd))
	{
		psus_warning("TCP set socket %d nonblocking fail.", psudata->hcsdata.tcp_fd);
	}

	tcp_connected = 0;

	//psus_hint("TCP Socket connecting to %s:%d...", IP2Str(psudata->tcp_addr.sin_addr.s_addr), ntohs(psudata->tcp_addr.sin_port));
	TcpTryConnect(psudata);
	return psudata->hcsdata.tcp_fd;
}

void CloseTcpSocket(psus_config *psudata)
{
	if (psudata->hcsdata.tcp_fd > INVAILDSOCKET)
	{
		close(psudata->hcsdata.tcp_fd);
		psudata->hcsdata.tcp_fd = INVAILDSOCKET;
		tcp_connected = 0;
	}
}

int TcpSocketStatus(int tcpFd, psus_config *psudata)
{
	int err = -1;
	socklen_t len = sizeof(int);

	if (tcpFd > INVAILDSOCKET)
	{
		if (getsockopt(tcpFd, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
		{
			CloseTcpSocket(psudata);
			psus_error("TCP getsockopt error[%d]: %s", errno, strerror(errno));
			return -2;
		}
		else
		{
			if (err != 0)
			{
				errno = err;
				//psus_error("TCP connect error[%d]:%s", err, strerror(errno));
				return -3;
			}
			else
			{
				psus_hint("getscketopt err=%d:%s",err,strerror(errno));
				return 0;
			}
		}
	}
	return -1;
}

/**
 * @brief 尝试连接TCP服务器
 *
 * @param psudata
 */
int TcpTryConnect(psus_config *psudata)
{
	int err = -1;
	socklen_t len = sizeof(int);

	if (psudata->hcsdata.tcp_fd > INVAILDSOCKET)
	{
		tcp_connected = 0;
		if (connect(psudata->hcsdata.tcp_fd, (struct sockaddr *)&psudata->hcsdata.tcp_addr, sizeof(struct sockaddr)) < 0)
		{
			if (errno != EINPROGRESS)
			{
				// psus_error("TCP Socket connect %s error [%d]: %s", psudata->network_tcpaddr, errno, strerror(errno));
				tcp_connected = 0;
				CloseTcpSocket(psudata);
				return -1;
			}
		}
	}
	return 0;
}

/**
 * @brief 根据规则回复数据给服务器
 *
 * @param psudata
 * @param buf
 * @param len
 * @return int
 */
int SendRspSocket(psus_config *psudata, char *buf, int len)
{
	switch (psudata->hcsdata.last_cmd_from)
	{
	case AEX_LCF_UDP:
		SendtoUdpServer(psudata,buf,len);
		break;
	case AEX_LCF_TCP:
		SendtoTcpServer(psudata,buf,len);
		break;
	case AEX_LCF_UART:
		if(psudata->hcsdata.bsuart.uart_used && psudata->hcsdata.bsuart.uart_fd != INVAILDSOCKET && psudata->hcsdata.bsuart.passto == AEX_UART_PACKNET){
			psus_hint("Send uart len=%d",len);
			write(psudata->hcsdata.bsuart.uart_fd,buf,len);
		}
		break;
	case AEX_LCF_MQTT:
		SendToMqttServer(psudata,buf,len);
		break;
	case AEX_LCF_ME:
		SendtoServer(buf,len);
		break;
	
	default:
		break;
	}
}

#ifdef USE_UEVENT
int StartUeventSocket(psus_config *psudata)
{
	struct sockaddr_nl addr;
	static int sz = 64 * 1024;

	if (psudata->uevent_fd > INVAILDSOCKET)
	{
		return psudata->uevent_fd;
	}
	memset(&addr, 0, sizeof(addr));
	addr.nl_family = AF_NETLINK;
	addr.nl_pid = getpid();
	addr.nl_groups = 0xffffffff;
	psudata->uevent_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
	if (psudata->uevent_fd < 0)
	{
		return 0;
	}

	setsockopt(psudata->uevent_fd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
	if (bind(psudata->uevent_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{
		close(psudata->uevent_fd);
		return 0;
	}
	return psudata->uevent_fd;
}

void CloseUeventSocket(psus_config *psudata)
{
	if (psudata->uevent_fd > INVAILDSOCKET)
	{
		close(psudata->uevent_fd);
		psudata->uevent_fd = INVAILDSOCKET;
	}
}

struct cooling_device
{
	const char *name;
	const char *action;
	char *value;
	char *oldvalue;
};

#ifdef USE_LUA
extern int lua_exec(char *luafile, int value, int old);
#endif

void parse_uevent(psus_config *psudata, const char *msg, struct cooling_device *cdev)
{
	while (*msg)
	{
		// printf("%s\n", msg);
		if (!strncmp(msg, "SUBSYSTEM=", 10))
		{
			msg += 10;
			cdev->name = msg;
		}
		else if (!strncmp(msg, "ACTION=", 7))
		{
			msg += 7;
			cdev->action = msg;
		}
		else if (!strncmp(msg, "VALUE=", 6))
		{
			msg += 6;
			cdev->value = msg;
		}
		else if (!strncmp(msg, "OLDVALUE=", 9))
		{
			msg += 9;
			cdev->oldvalue = msg;
		}
		while (*msg++)
			;
	}
	psus_hint("event { name=%s, action=%s, value=%s, old value=%s}",
			  cdev->name, cdev->action, cdev->value, cdev->oldvalue);
// 	if (strcmp(cdev->name, "aexgpio27") == 0)
// 	{
// 		// 找到我们需要的UEVENT
// 		unsigned int aexgpio = StrToInt(cdev->value);
// 		unsigned int oldvalue = StrToInt(cdev->oldvalue);
// #ifdef USE_HQJG_UDP
// 		// 华强景观灯协议上报
// 		hqjd_handle_uevent(oldvalue, aexgpio);
// #endif // USE_HQJG_UDP
// #ifdef USE_AEX_UDP
// 		aexudp_handle_uevent(oldvalue, aexgpio);
// #endif // USE_AEX_UDP
// 	   // MQTT协议上报

// #ifdef USE_LUA
// 		// 本地Lua脚本调用
// 		if (FileExist(psudata->lua_fn))
// 		{
// 			lua_exec(psudata->lua_fn, aexgpio, oldvalue);
// 		}
// #endif
	}
}
#endif

#ifndef USE_OPENWRT_UBUS
static char udpBuf[1024];
static struct ringbuffer udpFifo;
static char tcpBuf[1024];
static struct ringbuffer tcpFifo;
static char uartBuf[1024];
static struct ringbuffer uartFifo;
#endif

int parse_packnet_cmd(PRingBuffer ringBuf,unsigned char *buf, size_t len)
{
	int ret = -1;
	unsigned char *p = NULL;
	unsigned char cmdbuf[1024];
	int cmdlen = len > 1023 ? 1023 : len;
	psus_config *psudata = get_psus_data();

	memset(cmdbuf, 0, sizeof(cmdbuf));
	if (aexudp_find_begin(buf))
	{
		// 命令以开始标记，则说明是命令头，如果ringbuffer里有数据则是垃圾数据了
		ringbuffer_reset(&ringBuf);
		memcpy(cmdbuf, buf, len);
		cmdlen = len;
	}
	else
	{
		ringbuffer_in(&ringBuf, buf, len);
		cmdlen = ringbuffer_len(&ringBuf);
		cmdlen = cmdlen > 1023 ? 1023 : cmdlen;
		ringbuffer_out(&ringBuf, cmdbuf, cmdlen);
	}

	p = cmdbuf;
	while (*p)
	{
		while (!aexudp_find_begin(p) && cmdlen>0){
			p++; // 丢弃没用的字符
			cmdlen--;
		}
		// psus_hint("*p=%02x,psudata->last_cmd_from=%d",*p,psudata->last_cmd_from);

		if (aexudp_find_begin(p))
		{
			// 数据包为AEX自定义的边云测控协议
			ret = cmdlen - (p - cmdbuf);
			if (AEXUDP_GET_PACKET_LEN(p) <= ret)
			{
				PPKTPROPO pktpropo = aexudp_get_pktpropo(buf);
				// 解析处理边云测控协议
			#ifdef USE_AEX_UDP
				if(pktpropo != NULL){
					ret = pktpropo->func(p,AEXUDP_GET_PACKET_LEN(p));
				}
			#endif
				p += AEXUDP_GET_PACKET_LEN(p);
				ret = AEXUDP_GET_PACKET_LEN(p);
			}
			else
			{
				// 不足一个数据包
				// ret = cmdlen - (p - cmdbuf);
				ringbuffer_in(&ringBuf, p, ret); // 把不完整的数据包放入ringbuffer
				return ret;
			}
		}
		else{
			p++;
		}
	}
	return ret;
}

int WaitMessageAndHandle(char *configfn, int timeout)
{
	int i,iRet = 0, tcpFd, udpFd, uartFd, ueventFd;
	fd_set rfds, wfds;
	psus_config *psudata = get_psus_data();
	int len;
	unsigned char buf[256];
	struct sockaddr_in addr;

	// psus_hint("W:tcp %d,uart %d,udp %d,uevent %d",psudata->tcp_fd,psudata->uart_fd,psudata->udp_fd,psudata->uevent_fd);
	uartFd = psudata->hcsdata.bsuart.uart_fd;
	tcpFd = psudata->hcsdata.tcp_fd;
	udpFd = psudata->hcsdata.udp_fd;
#ifdef USE_UEVENT
	ueventFd = psudata->uevent_fd;
#endif

	// if (udpFd == INVAILDSOCKET)
	// {
	// 	// psus_error("Uart or network not ready,Sleep 30 sec.");
	// 	// return 0;
	// }

	// if (uartFd == INVAILDSOCKET)
	// {
	// 	// psus_error("Uart not ready.");
	// }
	// if (udpFd == INVAILDSOCKET)
	// {
	// 	psus_error("udp network not ready.");
	// }

	if(tcpFd == INVAILDSOCKET && udpFd == INVAILDSOCKET && uartFd == INVAILDSOCKET)
	{
		psus_error("No network or uart, sleep 30 sec.");
		sleep(30);
		return 0;
	}
	FD_ZERO(&rfds);
	// FD_SET(0, &rfds);

	if (udpFd != INVAILDSOCKET)
	{
		FD_SET(udpFd, &rfds);
	}
	if (uartFd != INVAILDSOCKET)
		FD_SET(uartFd, &rfds);
	else{
		// timeout = 20;
	}
	for(i=0;i<MAX_UART_NUM;i++){
		if(psudata->hcsdata.uarts[i].uart_fd > INVAILDSOCKET){
			FD_SET(psudata->hcsdata.uarts[i].uart_fd, &rfds);
		}
	}

	FD_ZERO(&wfds);
	if(tcpFd > INVAILDSOCKET){
		if (tcp_connected == 0)
		{
			FD_SET(tcpFd, &wfds);
		}else if(tcp_connected == 1){
			FD_SET(tcpFd, &rfds);
		}else{
			timeout = 20;
		}
	}else{
		timeout = 20;
	}

#ifdef USE_UEVENT
	if (ueventFd > 0)
	{
		FD_SET(ueventFd, &rfds);
	}
#endif

	struct timeval tv = {timeout, 0};
	psus_log(10, "Waiting for DATA(%d.uid=%d,nid=%d,%d,%d,max=%d)...", timeout,uartFd, tcpFd, udpFd, ueventFd, max_value(4, tcpFd, udpFd, uartFd, ueventFd));
	// 至少保证超时时间不低于30秒，以避免有问题的时候过于频繁的循环
	if (tv.tv_sec == -1 || timeout == 0 || timeout == -1)
	{
		iRet = select(max_value(4, tcpFd, udpFd, uartFd, ueventFd) + 1, &rfds, &wfds, NULL, NULL);
		psus_log(10, "iRet=%d", iRet);
	}
	else
	{
		tv.tv_sec = timeout > 1200 ? 1200:timeout;
		iRet = select(max_value(4, tcpFd, udpFd, uartFd, ueventFd) + 1, &rfds, &wfds, NULL, &tv);
		psus_log(10, "iRet=%d,timeout=%d", iRet, tv.tv_sec);
	}
	if (iRet == 0)
	{
		if (FD_ISSET(tcpFd, &rfds))
		{
			// CloseTcpSocket(psudata);
		}
		if (FD_ISSET(uartFd, &rfds))
		{
			// CloseUart(psudata);
		}
		if (FD_ISSET(udpFd, &rfds))
		{
			// CloseUdpSocket(psudata);
		}
#ifdef USE_UEVENT
		if (FD_ISSET(ueventFd, &rfds))
		{
			// CloseUeventSocket(psudata);
		}
#endif
		return 0; // 等待超时，进入下一次循环
	}
	else if (iRet < 0)
	{
		if(errno == EINTR){
			//慢系统调用函数如何处理中断信号EINTR,参考：https://blog.csdn.net/bingqingsuimeng/article/details/50460462
			// psus_error("Select  error return %d,%s", iRet,strerror(errno));
			return 0;
		}else{
			// psus_error("Select  error return %d,%s", iRet,strerror(errno));
		}
	}
	else
	{
		if (tcpFd != INVAILDSOCKET && FD_ISSET(tcpFd, &rfds))
		{
			// 这里处理的是服务器主动向客户端发送的消息，处理完以后客户端沿沿原途径做出回应
			memset(buf, 0, sizeof(buf));
			len = read(tcpFd, buf, sizeof(buf));
			psudata->hcsdata.last_cmd_from = AEX_LCF_TCP;
			if (len > 0 && tcpFd > 0)
			{
#ifdef PSU_DEBUG
				psus_hint("TCPNET[%d]:", len);
				dump_buffer("",buf, len);
#endif
				if(parse_packnet_cmd(&tcpFifo,buf, len)<0){
				}
			}
		}
		if (tcpFd != INVAILDSOCKET && FD_ISSET(tcpFd, &wfds))
		{
			switch (TcpSocketStatus(tcpFd, psudata))
			{
			case 0:
				psus_hint("TCP Connected.");
				tcp_connected = 1;
				break;
			case -1:
				psus_hint("TCP Write.");
				break;
			case -2:
			case -3:
				//psus_error("TCP Connect fail.");
				tcp_connected = -3;
				break;
			default:
				break;
			}
		}
		if (uartFd != INVAILDSOCKET && FD_ISSET(uartFd, &rfds))
		{
			// 这里处理通过UART收到的命令
			//_log(psus_data.log_file,psus_data.flag,"UART:");
			memset(buf, 0, sizeof(buf));
			len = read(uartFd, buf, sizeof(buf));
			psudata->hcsdata.last_cmd_from = AEX_LCF_UART;
			if (len > 0)
			{
#ifdef PSU_DEBUG
				psus_hint("UART RECV[%d]", len);
				dump_buffer("",buf, len > 16 ? 16 : len);
#endif
				switch (psudata->hcsdata.bsuart.passto)
				{
				case AEX_UART_PACKNET:
					// psus_hint("UART as packnet.");
					aexgpio_set_bus_status(1);
					psudata->hcsdata.last_cmd_from = AEX_LCF_UART;
					if(parse_packnet_cmd(&uartFifo,buf, len)<0){
					}
					// psus_hint("parse_packnet_cmd end.");
					break;
				case AEX_UART_PASSTO_LUA:
#ifdef USE_LUA
					lua_on_recv_from_uart(psudata->lua_fn, buf, len);
#endif
					break;
				}
			}
		}
		for(i=0;i<MAX_UART_NUM;i++){
			if(psudata->hcsdata.uarts[i].uart_fd > INVAILDSOCKET && FD_ISSET(psudata->hcsdata.uarts[i].uart_fd, &rfds)){
				// 这里处理通过UART收到的命令
				memset(buf, 0, sizeof(buf));
				len = read(psudata->hcsdata.uarts[i].uart_fd, buf, sizeof(buf));
				psudata->hcsdata.last_cmd_from = AEX_LCF_UART;
				if (len > 0)
				{
#ifdef PSU_DEBUG
					psus_hint("UART%d RECV[%d]",i, len);
					dump_buffer("",buf, len > 16 ? 16 : len);
#endif
					switch (psudata->hcsdata.uarts[i].passto)
					{
					case AEX_UART_PACKNET:
						// psus_hint("UART%d as packnet.",i);
						// aexgpio_set_bus_status(1);
						// psudata->hcsdata.last_cmd_from = AEX_LCF_UART;
						// if(parse_packnet_cmd(&uartFifo,buf, len)<0){
						// }
						// psus_hint("parse_packnet_cmd end.");
						break;
					case AEX_UART_PASSTO_LUA:
#ifdef USE_LUA
						lua_on_recv_from_uart(psudata->lua_fn, buf, len);
#endif
						break;
					case AEX_UART_PACKET_MODBUS:
						// psus_hint("UART%d as modbus.",i);
						// 处理Modbus数据包
						// if (modbus_parse(psudata->hcsdata.uarts[i].uart_fd, buf, len) < 0)
						// {
						// 	psus_error("Modbus parse error.");
						// }
						break;
					case AEX_UART_PACKET_SERVER:
						// 收到串口数据包，直接转发给服务器
						psus_hint("UART%d as server.",i);
						psudata->hcsdata.last_cmd_from = AEX_LCF_UART;
						// 直接转发数据包给服务器
						{
							char pbuf[255];
							PPKTPROPO handle = aexudp_get_default_prkpropo();
							if(handle != NULL){
								unsigned char index=0;
								unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(pbuf));

								memset(pbuf,0,sizeof(pbuf));
								AEXUDP_SET_BEGIN(pbuf,handle->start);
								AEXUDP_SET_INDEX(pbuf,aexudp_get_packnet_index());
								AEXUDP_SET_CMD(pbuf,AEX_CMD_TRANSDATA);
								AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(pbuf),aexgpio_get_mod_addr());
								AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(pbuf),0);				
								pdata[index++] = i&0xFF;		//串口序号 
								if(len>(AEXUDP_PACKNET_MAX_PLOAD)){
									len = AEXUDP_PACKNET_MAX_PLOAD-1;	//最大负载长度
								}
								memcpy(&pdata[index],buf,len);		//复制串口数据
								index += len;
								AEXUDP_SET_LEN(pbuf,index+AEXUDP_DATA_GET_PAYLOADINDEX());
								if(handle->encrypt){
									handle->encrypt(pbuf,AEXUDP_GET_LEN(pbuf));
								}else{
									AEXUDP_SET_CRC(pbuf);
								}
								AEXUDP_SET_END(pbuf,handle->end);
								SendtoServer(pbuf,AEXUDP_GET_PACKET_LEN(pbuf));
							}
						}
						break;
					}
				}
			}
		}
		if (udpFd != INVAILDSOCKET && FD_ISSET(udpFd, &rfds))
		{
			// 这里处理的是服务器主动向客户端发送的消息，处理完以后客户端沿沿原途径做出回应
			// psus_hint("%s:%d",__func__,__LINE__);
			len = aexudp_recv_from_udp(udpFd, buf, sizeof(buf));
			if(len > 0)
			{
				// 解析处理边云测控协议
				parse_packnet_cmd(&udpFifo, buf, len);
			}
		}
#ifdef USE_UEVENT
		if (ueventFd > 0 && FD_ISSET(ueventFd, &rfds))
		{
			// 这里处理UEVENT的消息
			size_t addr_len = sizeof(struct sockaddr);
			memset(buf, 0, sizeof(buf));
			len = read(ueventFd, buf, sizeof(buf));
			psus_hint("UEVENT:%s", buf);
			if (len > 0 && ueventFd > 0)
			{
				struct cooling_device cdev;
				memset(&cdev, 0x0, sizeof(cdev));
				// 下面解析UEVEENT
				parse_uevent(psudata, buf, &cdev);
			}
		}
#endif
		/*
		if (FD_ISSET(0, &rfds))
		{
			psus_log(10,"From stdin");
			memset(buf, 0, sizeof(buf));
			scanf("%s", buf);
			rader_cmd_from_stdin(uartFd, buf, strlen(buf));
		}
		*/
		iRet = 0;
	}

	// SYS_PRINT("====WaitMessageAndHandle===end====");
	return iRet;
}

/**
 * @brief 为延迟任务派生子进程
 *
 * @param seconds
 * @param mseconds
 * @return int
 * 		返回 -1 表示派生子进程失败，无法做延时任务了
 * 			0：表示是父进程，子进程已启动，继续其他的工作
 * 			>0 : 表示在子进程中，并已经延时结束，一般延迟任务完成后要退出子进程
 */
int fok_for_timer(unsigned int mseconds, unsigned int seconds)
{
	struct timeval temp;

	int fpid = fork();
	if (fpid < 0)
	{
		psus_error("error in fork for delay work!");
	}
	else if (fpid == 0)
	{
		// 子进程
		// psus_hint("==for timer before==");
		temp.tv_sec = seconds + mseconds / 1000;
		temp.tv_usec = (mseconds % 1000) * 1000;
		if (select(0, NULL, NULL, NULL, &temp) == 0)
		{
			// psus_hint("==timerout==");
		}
		// psus_hint("==for timer start==");
	}
	else
	{
		// 父进程，服务程序退出父进程
		int status = 10;

		waitpid(-1, &status, WNOHANG);
	}
	return fpid;
}

/**
 * @brief 延迟任务结束后的进程收尾工作
 *
 */
void exit_for_fok()
{
	CloseUart(get_psus_data());
	// psus_hint("E1");
	CloseUdpSocket(get_psus_data());
	// psus_hint("E2");
	CloseTcpSocket(get_psus_data());
#ifdef USE_UEVENT
	// psus_hint("E3");
	CloseUeventSocket(get_psus_data());
#endif
#ifdef USE_MQTT
// psus_hint("E4");
//  mqtt_quit();
#endif
	// psus_hint("E5");
	clear_config(get_psus_data());
	psus_hint("==Pid %d  exit.==", getpid());
	exit(0);
}

/**
 * @brief 发送IO状态心跳的函数
 *
 */
void heart_handler()
{
// 心跳时间到
// #ifdef USE_HQJG_UDP
// 	// 使用华强景观灯协议发送心跳
// 	hqjg_report_iostatus(CMD_HQJD_AUTO_HEART, 0xFF);
// #endif
// #ifdef USE_AEX_UDP
// 	// 使用AEX UDP协议 发送心跳
// #endif
// #ifdef USE_MQTT
// 	// 使用MQTT发送心跳
// #endif
	int buf[100];

	aexudp_buid_heart_packnet(buf,sizeof(buf));
	// SendtoServer(buf,AEXUDP_GET_PACKET_LEN(buf));
}

void modbus_update(void *arg)
{
	psus_config *psudata = get_psus_data();

	//加热器通过Modbus更新流量、进口温度、出口温度的数据
	modbusmain();
}

void check_input_handler(void *arg)
{
	// psus_hint("%s",__func__);
	modgpio_chkinput();
}


#define MAX_TIMNER_NUM			10
#define HCSRV_MODBUS_INTERVAL	10		//流量、进口温度、出口温度每隔10秒更新一次

#ifdef MT_TIMER
	TIMER_CREATE(Heating);
	static int heart_timer=0;
	static int modbus_update_timer=0;
	static int check_input_timer=0;
#endif

void start_timers()
{
#ifdef MT_TIMER
	struct itimerspec itimespec;

	TIMER_INIT(Heating, MAX_TIMNER_NUM);
	itimespec.it_value.tv_sec = KC031SRV_HEART_DELAY;
	itimespec.it_value.tv_nsec = 0;
	itimespec.it_interval.tv_sec = KC031SRV_HEART_INTERVAL;
	itimespec.it_interval.tv_nsec = 0;
	
	heart_timer = TIMER_ADD(Heating, &itimespec, -1, heart_handler, NULL, NULL);
	itimespec.it_value.tv_sec = HCSRV_HEART_DELAY;
	itimespec.it_value.tv_nsec = 0;
	itimespec.it_interval.tv_sec = get_heating_inv();
	itimespec.it_interval.tv_nsec = 0;
	modbus_update_timer = TIMER_ADD(Heating, &itimespec, -1, modbus_update, NULL, NULL);

	// itimespec.it_value.tv_sec = 0;
	// itimespec.it_value.tv_nsec = KC031SRV_CHKINPUT_DELAY;
	// itimespec.it_interval.tv_sec = 0;
	// itimespec.it_interval.tv_nsec = KC031SRV_CHKINPUT_INTERVAL;
	// check_input_timer = TIMER_ADD(Heating, &itimespec, -1, check_input_handler, NULL, NULL);
#endif
}

void stop_timers()
{
#ifdef MT_TIMER
	TIMER_DEL(Heating, heart_timer);
	TIMER_DEL(Heating, modbus_update_timer);
	TIMER_CLEAR(Heating);
	TIMER_DEINIT(Heating);
#endif
}

static int g_singnal_exit=0;
void signal_func(int sign_no)
{
	switch (sign_no)
	{
	case SIGINT:
		psus_warning("I have get SIGINT");
		g_singnal_exit=1;
		break;
	case SIGSTOP:
	case SIGKILL:
	case SIGABRT:
	case SIGQUIT:
		psus_warning("I have get SIGQUIT");
		g_singnal_exit=1;
		break;
	case SIGALRM:
		break;
	case SIGSEGV:
		psus_warning("I have get SIGSEGV %d", getpid());
		g_singnal_exit=1;
		break;
	default:
		psus_error("unknow sign :%d", sign_no);
		break;
	}
}

/**
 * @brief 写进程ID到文件，以备进程通讯时使用
 *
 * @param fn
 */
void write_id_to_file(char *fn)
{
	FILE *pid_fd;
	pid_fd = fopen(fn, "w+");
	if (pid_fd != NULL)
	{

		fprintf(pid_fd, "%d", getpid());
		fclose(pid_fd);
	}
}

/**
 * @brief 从文件中读出进城ID（之前运行的进程）
 *
 * @param fn
 * @return int
 */
int read_id_to_file(char *fn)
{
	int pid = 0;
	FILE *pid_fd;
	pid_fd = fopen(fn, "r");
	if (pid_fd != NULL)
	{

		fscanf(pid_fd, "%d", &pid);
		fclose(pid_fd);
	}
	return pid;
}

int main(int argc, char *argv[])
{
	pid_t fpid; // fpid表示fork函数返回的值
	char fn[MAX_PATH];
	char tmp[128];
	int i = 0;
	psus_config *psudata = get_psus_data();

	// psus_hint("=============KC031 service start====================");

	memset(fn, 0, sizeof(fn));
	if (CheckCmdLine(argc, argv, "v"))
	{
		printf("%s", app_version_get());
		return 0;
	}
	if (GetCmdParamValue(argc, argv, "genuuid", tmp))
	{
		char uuid[40];

		gen_uuid(uuid);
		printf("%s",uuid);
		return 0;
	}

	if (!GetCmdParamValue(argc, argv, "config", fn))
	{
		strcpy(fn, "/etc/kc031srv/kc031srv.conf");
	}
	// printf("%s",argv[0]);
	mkdir("/etc/kc031srv", 0777);
	psus_hint("Use config file : %s", fn);

	LoadPsuConfig(fn);
	// signal(SIGINT, signal_func);
	// signal(SIGQUIT, signal_func);
	signal(SIGALRM, signal_func);
	// signal(SIGSEGV, signal_func);

	memset(tmp, 0, sizeof(tmp));
	if (GetCmdParamValue(argc, argv, "log", tmp))
	{
		if (psus_data.log_file != NULL)
			free(psus_data.log_file);
		psus_data.log_file = strdup(tmp);
	}
	psus_hint("Use log file : %s", psus_data.log_file);
	memset(tmp, 0, sizeof(tmp));
	ExtractFilePath(psus_data.log_file, tmp);
	mkdir(tmp, 0777);
	memset(tmp, 0, sizeof(tmp));

	if (GetCmdParamValue(argc, argv, "event", tmp))
	{
		char cmd[200];
		int cmdlen = sizeof(cmd);
		unsigned short value = 0, oldvalue = 0;
		PPKTPROPO handle = aexudp_get_default_prkpropo();

		memset(cmd, 0, sizeof(cmd));
		psus_hint("EVENT:%s", tmp);
		sscanf(tmp, "%X %X", &value, &oldvalue);
		psus_hint("\t0x%04X,0x%04X", value, oldvalue);

		if(handle != NULL){
			unsigned char index=0;
			unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(cmd));

			memset(cmd,0,sizeof(cmd));
			AEXUDP_SET_BEGIN(cmd,handle->start);
			AEXUDP_SET_INDEX(cmd,aexudp_get_packnet_index());
			AEXUDP_SET_CMD(cmd,AEX_CMD_DIEVENT);
			AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(cmd),aexgpio_get_mod_addr());
			AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(cmd),0);	
			pdata[index++] = (value & 0xFF00) >> 8;
			pdata[index++] = value & 0xFF;
			pdata[index++] = (oldvalue & 0xFF00) >> 8;
			pdata[index++] = oldvalue & 0xFF;
			AEXUDP_SET_LEN(cmd,index+2);
			if(handle->encrypt){
				handle->encrypt(cmd,AEXUDP_GET_LEN(cmd));
			}else{
				AEXUDP_SET_CRC(cmd);
			}
			AEXUDP_SET_END(cmd,handle->end);
			SendtoMe(cmd, AEXUDP_GET_PACKET_LEN(cmd));
		}
		return 0; // 结束任务
	}

	if (GetCmdParamValue(argc, argv, "pid", tmp))
	{
		if (psus_data.main_pid != NULL)
			free(psus_data.main_pid);
		psus_data.main_pid = strdup(tmp); // 取得新的PID的文件名
	}
	int pid = read_id_to_file(psus_data.main_pid);
	psus_hint("Use pid file : %s,pid=%d.", psus_data.main_pid, pid);
	if (pid > 0)
	{
		// 读取到了之前的进程ID，我们认为系统有此进程，如果程序退出没有正确删除进程ID文件，则手工删除重新执行即可
		// 这里我们就粗暴的认为系统已经有这个进程了
		memset(tmp, 0, sizeof(tmp));
		if (GetCmdParamValue(argc, argv, "cmd", tmp))
		{
			char cmd[200];
			int cmdlen = sizeof(cmd);

			memset(cmd, 0, sizeof(cmd));
			HexDecode(tmp, strlen(tmp), cmd, &cmdlen);
			SendtoMe(cmd, cmdlen);
			return 0; // 结束任务
		}
	}

	if (CheckCmdLine(argc, argv, "d"))
	{
		psus_log(10, "Using deamon runing parameter.");
		fpid = fork();
		if (fpid < 0)
		{
			psus_error("error in fork!");
			return -1;
		}
		else if (fpid == 0)
		{
			// 子进程
			psus_log(10, "Child process runing(%d)...", getpid());
		}
		else
		{
			// 父进程，服务程序退出父进程
			psus_log(10, "Child process %d runing,Parent process exit.", fpid);
			return 0;
		}
	}
	write_id_to_file(psus_data.main_pid);
	psus_hint("kc031 process id is %d", getpid());
	ringbuffer_init(&uartFifo, uartBuf, sizeof(uartBuf));
	ringbuffer_init(&udpFifo, udpBuf, sizeof(udpBuf));
	ringbuffer_init(&tcpFifo, tcpBuf, sizeof(tcpBuf));
	// 启动服务处理循环
	// 处理命令接口
	int iRet = 0;
	aexgpio_init();
#ifdef USE_MQTT
	mqtt_start();
#endif
#ifdef USE_UEVENT
	StartUeventSocket(psudata);
#endif
	// start_chkinput();
	start_timers();
	do
	{
		if(OpenUart(&psudata->hcsdata.bsuart)){
			// psus_hint("bsuart:%d",psudata->hcsdata.bsuart.uart_fd);
			
		}
		for(i=0;i<MAX_UART_NUM;i++){
			if(psudata->hcsdata.uarts[i].uart_used){
				OpenUart(&psudata->hcsdata.uarts[i]);
			}
		}
		StartTcpSocket(psudata);
		StartUdpSocket(psudata);
		iRet = WaitMessageAndHandle(fn, psudata->hcsdata.selectTimeout);
		// psus_log(10, "WaitMessageAndHandle iRet=%d", iRet);
		if(g_singnal_exit){
			psus_warning("Get singal exit,exit now.");
			iRet = -1; // 退出循环
		}
	} while (iRet >= 0);
	psus_hint("Kc031 Process %d end.", getpid());
	stop_timers();
#ifdef USE_MQTT
	mqtt_quit();
#endif

	CloseUart(&psudata->hcsdata.bsuart);
	for(i=0;i<MAX_UART_NUM;i++){
		if(psudata->hcsdata.uarts[i].uart_used){
			CloseUart(&psudata->hcsdata.uarts[i]);
		}
	}
	CloseUdpSocket(psudata);
	CloseTcpSocket(psudata);
#ifdef USE_UEVENT
		CloseUeventSocket(get_psus_data());
#endif
	remove(psus_data.main_pid);
	clear_config(get_psus_data());
	stop_timers();
	return 0;
}
